package lesson5.example4;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.lang.instrument.ClassDefinition;
import java.lang.instrument.Instrumentation;

public class MyAgent {
	public static void agentmain(String agentArgs, Instrumentation instrumentation){ 
		System.out.println("dynamic attach ...");
		 try {
	            File file = new File("/media/mazhi/sourcecode/workspace/projectjava5/bytecode-examples/bytecode-example-5-02/"+
	                                 "target/test-classes/lesson5/example4/User.class");
	            ClassFileWatcher watcher = new ClassFileWatcher(instrumentation, file);
	            watcher.start();
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	    }

	    private static class ClassFileWatcher extends Thread {
	        private File classFile;
	        private long lastModified;
	        private Instrumentation instrumentation;
	        private boolean firstRun = true;

	        ClassFileWatcher(Instrumentation instrumentation, File classFile) {
	            this.classFile = classFile;
	            this.instrumentation = instrumentation;
	            lastModified = classFile.lastModified();
	        }

	        @Override
	        public void run() {
	            while (true) {
	                if (firstRun || (lastModified != classFile.lastModified())) {
	                    firstRun = false;
	                    lastModified = classFile.lastModified();
	                    redefineClass(instrumentation, classFile);
	                }
	                System.out.println("检测文件的变化...");
	                try {
	                    Thread.sleep(10000L);
	                } catch (InterruptedException e) {
	                    e.printStackTrace();
	                }
	            }
	        }

	    }

	    private static void redefineClass(Instrumentation instrumentation, File classFile) {
	    	System.out.println("检测到文件的变化！");
	        byte[] bytes = new byte[(int) classFile.length()];
	        DataInputStream in;
	        try {
	            in = new DataInputStream(new FileInputStream(classFile));
	            in.readFully(bytes);
	            in.close();
	            ClassDefinition cd = new ClassDefinition(Class.forName("lesson5.example4.User"), bytes);
	            /**
	             * 重新定义类，不是使用 transformer 修饰，而是把处理结果(bytecode)直接给JVM。
	             * 调用此方法同样只能修改方法体，不能变更方法签名、增加和删除方法/类的成员属性
	             */
	            instrumentation.redefineClasses(cd);
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	    }
}
